
#include "main.h"


vu32 g_vu32SysTickCount = 0;
vu32 g_vu32SysTickSecond = 0;
u8 g_u8CurState = STATE_UNKNOWN;
u8 g_u8OsType = OSTYPE_UNKNOWN;
u8 g_u8TestCode = 0;
#if		defined(BSP_DEVICE_TOUCH)
u8 g_u8MyAddr = DEV_TOUCH;
u32 g_u32BuzzerDelay = 0;
USB_OTG_CORE_HANDLE g_UsbOtgDevice;
TOUCHCONFIG_DATA g_TCD =
{
	DATA_FILTER_NUM_DEF, DATA_INPUT_MODE_MOUSE,
	DATA_PWM_DEF, DATA_PWM_DEF, DATA_PWM_DEF, DATA_PWM_DEF,
	DATA_TIME_TAP_DEF, DATA_TIME_LTAP_DEF,
	DATA_AREA_TAP_DEF, DATA_AREA_DTAP_DEF, DATA_AREA_PALM_DEF,
	DATA_BEEP_ALERT_DEF, DATA_BEEP_CLICK_DEF,
	DATA_TOUCH_NOSEND_DEF,
};
GESTURE_DATA g_GD = {
	{0,},
};
u32 g_u32TimeTap = 0;
u32 g_u32TimeLTap = 0;
float g_fAreaTap = 0;
float g_fAreaDTap = 0;
float g_fAreaPalm = 0;
#elif	defined(BSP_DEVICE_CAMERA)
u8 g_u8MyAddr = DEV_CAMERA1;
CAMERACONFIG_DATA g_CCD =
{
	DATA_YCENTER_DEF, DATA_XSTART_DEF, DATA_XEND_DEF, DATA_THRESHOLD_DEF,
	DATA_MINWIDTH_DEF, DATA_AVERAGELIGHT_DEF,
	0,0,
};
#endif	//BSP_DEVICE_xxx


static STATE_PROC _CurStateProc = NULL;

static void procState(u8 state);
static void stateInit(u8 state);
static void stateTouch(u8 state);
static void stateSideview(u8 state);
static void stateDetection(u8 state);
static void stateCalibration(u8 state);


int main()
{
	time_t tBuildTime = Util_GetBuildTime();
	u32 uDelay_ms = 0;
	u16 uData, uTotalSize = 0;

	if (SysTick_Config(SystemCoreClock / 1000)) /* 1msec */
		while (1);

	/* NVIC_PriorityGroup_2 : 0~3, 0~3 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

	Uart_Init();
#if		defined(BSP_DEVICE_TOUCH)
	printf("\r\n <<< App_Touch Controller Start >>> \r\n");
#elif	defined(BSP_DEVICE_CAMERA)
	printf("\r\n <<< App_Camera Controller Start >>> \r\n");
#endif	//BSP_DEVICE_xxx
	g_u8MyAddr = Util_BoardAddr();
	printf(">    BoardAddr : 0x%02X\r\n", g_u8MyAddr);
	printf("> StartAddress : 0x%X\r\n", SCB->VTOR);
	printf("> VersionInfo  : 0x%04X\r\n", MODULE_VERSION);
	printf("> BuildDate    : %s\r\n", ctime(&tBuildTime));

	Led_Init();
	FLASH_If_Init();
	EE_Init();

	EE_ReadVariable(g_VirtAddVarTab[IAP_SAVE_APP_CHECK], &uData);
	printf(">      IAP_SAVE_APP_CHECK : 0x%X\r\n", uData);
	EE_ReadVariable(g_VirtAddVarTab[IAP_SAVE_APP_TOTAL_SIZE], &uData);
	printf("> IAP_SAVE_APP_TOTAL_SIZE : %d\r\n", uData);
	EE_ReadVariable(g_VirtAddVarTab[IAP_SAVE_IAP_CHECK], &uData);
	printf(">      IAP_SAVE_IAP_CHECK : 0x%X\r\n", uData);
	EE_ReadVariable(g_VirtAddVarTab[IAP_SAVE_IAP_TOTAL_SIZE], &uTotalSize);
	printf("> IAP_SAVE_IAP_TOTAL_SIZE : %d\r\n\r\n", uTotalSize);

	if ((0x1234 == uData) && uTotalSize)
	{
		if (0 == Util_FirmwareUpdate(SCB->VTOR, uTotalSize))
		{
			uData = 0;
			EE_WriteVariable(g_VirtAddVarTab[IAP_SAVE_IAP_CHECK], uData);
			EE_WriteVariable(g_VirtAddVarTab[IAP_SAVE_IAP_TOTAL_SIZE], uData);

			uDelay_ms = g_vu32SysTickCount + 1000;
			while (uDelay_ms <= g_vu32SysTickCount);
			NVIC_SystemReset();
		}
	}

	EE_ReadVariable(g_VirtAddVarTab[APP_EEPROM_START], &uData);
#if		defined(BSP_DEVICE_TOUCH)
	if (DATA_EEPROM_START_VAL != uData)
	{
		printf(">		 APP_EEPROM_START : %04X != %04X\r\n", DATA_EEPROM_START_VAL, uData);
		printf("<<< EEPROM ALL DATA RESET >>>\r\n\r\n");

		g_TCD.bFilterNum = DATA_FILTER_NUM_DEF;
		g_TCD.bInputMode = DATA_INPUT_MODE_MULTI;
		for (u8 i=0; i<DATA_PWM_NUM; i++) {
			g_TCD.bPWMs[i] = DATA_PWM_DEF;
		}
		g_TCD.bTimeTap = DATA_TIME_TAP_DEF;
		g_TCD.bTimeLTap = DATA_TIME_LTAP_DEF;
		g_TCD.bAreaTap = DATA_AREA_TAP_DEF;
		g_TCD.bAreaDTap = DATA_AREA_DTAP_DEF;
		g_TCD.bAreaPalm = DATA_AREA_PALM_DEF;
		g_TCD.bBeepAlert = DATA_BEEP_ALERT_DEF;
		g_TCD.bBeepClick = DATA_BEEP_CLICK_DEF;
		g_TCD.bTouchNoSend = DATA_TOUCH_NOSEND_DEF;

		EE_WriteVariable(g_VirtAddVarTab[TOUCH_FILTER_NUM], g_TCD.bFilterNum);
		EE_WriteVariable(g_VirtAddVarTab[TOUCH_INPUT_MODE], g_TCD.bInputMode);
		for (u8 i=0; i<DATA_PWM_NUM; i++) {
			g_TCD.bPWMs[i] = Pwm_Set(i, g_TCD.bPWMs[i]);
			EE_WriteVariable(g_VirtAddVarTab[TOUCH_PWM_CH1 + i], g_TCD.bPWMs[i]);
		}
		EE_WriteVariable(g_VirtAddVarTab[TOUCH_TIME_TAP], g_TCD.bTimeTap);
		EE_WriteVariable(g_VirtAddVarTab[TOUCH_TIME_LTAP], g_TCD.bTimeLTap);
		EE_WriteVariable(g_VirtAddVarTab[TOUCH_AREA_TAP], g_TCD.bAreaTap);
		EE_WriteVariable(g_VirtAddVarTab[TOUCH_AREA_DTAP], g_TCD.bAreaDTap);
		EE_WriteVariable(g_VirtAddVarTab[TOUCH_AREA_PALM], g_TCD.bAreaPalm);
		EE_WriteVariable(g_VirtAddVarTab[TOUCH_BEEP_ALERT], g_TCD.bBeepAlert);
		EE_WriteVariable(g_VirtAddVarTab[TOUCH_BEEP_CLICK], g_TCD.bBeepClick);
		EE_WriteVariable(g_VirtAddVarTab[TOUCH_TOUCH_NOSEND], g_TCD.bTouchNoSend);

		memcpy(&uData, &g_GD.g[GE_DRAGUP], 2);		EE_WriteVariable(g_VirtAddVarTab[GESTURE_UDRAG], uData);
		memcpy(&uData, &g_GD.g[GE_DRAGRIGHT], 2);	EE_WriteVariable(g_VirtAddVarTab[GESTURE_RDRAG], uData);
		memcpy(&uData, &g_GD.g[GE_DRAGDOWN], 2);	EE_WriteVariable(g_VirtAddVarTab[GESTURE_DDRAG], uData);
		memcpy(&uData, &g_GD.g[GE_DRAGLEFT], 2);	EE_WriteVariable(g_VirtAddVarTab[GESTURE_LDRAG], uData);
		memcpy(&uData, &g_GD.g[GE_TAP], 2);			EE_WriteVariable(g_VirtAddVarTab[GESTURE_TAP], uData);
		memcpy(&uData, &g_GD.g[GE_TAPDOUBLE], 2);	EE_WriteVariable(g_VirtAddVarTab[GESTURE_DTAP], uData);
		memcpy(&uData, &g_GD.g[GE_TAPLONG], 2);		EE_WriteVariable(g_VirtAddVarTab[GESTURE_LTAP], uData);

		uData = DATA_EEPROM_START_VAL;
		EE_WriteVariable(g_VirtAddVarTab[APP_EEPROM_START], uData);
	}
	else
	{
		EE_ReadVariable(g_VirtAddVarTab[TOUCH_FILTER_NUM], &uData);
		g_TCD.bFilterNum = max(min(uData, DATA_FILTER_NUM_MAX), DATA_FILTER_NUM_MIN);
		for (u8 i=0; i<DATA_PWM_NUM; i++) {
			EE_ReadVariable(g_VirtAddVarTab[TOUCH_PWM_CH1], &uData);
			g_TCD.bPWMs[i] = Pwm_Set(i, uData);
		}
		EE_ReadVariable(g_VirtAddVarTab[TOUCH_INPUT_MODE], &uData);
		g_TCD.bInputMode = max(min(uData, DATA_INPUT_MODE_MULTI), DATA_INPUT_MODE_MOUSE);
		EE_ReadVariable(g_VirtAddVarTab[TOUCH_TIME_TAP], &uData);
		g_TCD.bTimeTap = max(min(uData, DATA_TIME_TAP_MAX), DATA_TIME_TAP_MIN);
		EE_ReadVariable(g_VirtAddVarTab[TOUCH_TIME_LTAP], &uData);
		g_TCD.bTimeLTap = max(min(uData, DATA_TIME_LTAP_MAX), DATA_TIME_LTAP_MIN);
		EE_ReadVariable(g_VirtAddVarTab[TOUCH_AREA_TAP], &uData);
		g_TCD.bAreaTap = max(min(uData, DATA_AREA_TAP_MAX), DATA_AREA_TAP_MIN);
		EE_ReadVariable(g_VirtAddVarTab[TOUCH_AREA_DTAP], &uData);
		g_TCD.bAreaDTap = max(min(uData, DATA_AREA_DTAP_MAX), DATA_AREA_DTAP_MIN);
		EE_ReadVariable(g_VirtAddVarTab[TOUCH_AREA_PALM], &uData);
		g_TCD.bAreaPalm = max(min(uData, DATA_AREA_PALM_MAX), DATA_AREA_PALM_MIN);
		EE_ReadVariable(g_VirtAddVarTab[TOUCH_BEEP_ALERT], &uData);
		g_TCD.bBeepAlert = uData;
		EE_ReadVariable(g_VirtAddVarTab[TOUCH_BEEP_CLICK], &uData);
		g_TCD.bBeepClick = uData;
		EE_ReadVariable(g_VirtAddVarTab[TOUCH_TOUCH_NOSEND], &uData);
		g_TCD.bTouchNoSend = uData;

		EE_ReadVariable(g_VirtAddVarTab[GESTURE_UDRAG], &uData);	memcpy(&g_GD.g[GE_DRAGUP], &uData, 2);
		EE_ReadVariable(g_VirtAddVarTab[GESTURE_RDRAG], &uData);	memcpy(&g_GD.g[GE_DRAGRIGHT], &uData, 2);
		EE_ReadVariable(g_VirtAddVarTab[GESTURE_DDRAG], &uData);	memcpy(&g_GD.g[GE_DRAGDOWN], &uData, 2);
		EE_ReadVariable(g_VirtAddVarTab[GESTURE_LDRAG], &uData);	memcpy(&g_GD.g[GE_DRAGLEFT], &uData, 2);
		EE_ReadVariable(g_VirtAddVarTab[GESTURE_TAP], &uData);		memcpy(&g_GD.g[GE_TAP], &uData, 2);
		EE_ReadVariable(g_VirtAddVarTab[GESTURE_DTAP], &uData);		memcpy(&g_GD.g[GE_TAPDOUBLE], &uData, 2);
		EE_ReadVariable(g_VirtAddVarTab[GESTURE_LTAP], &uData);		memcpy(&g_GD.g[GE_TAPLONG], &uData, 2);
	}
	g_u32TimeTap = g_TCD.bTimeTap * 100;	//[*100 msec]
	g_u32TimeLTap = g_TCD.bTimeLTap * 100;	//[*100 msec]
	g_fAreaTap = g_TCD.bAreaTap * 0.001;	//[*0.1 %]
	g_fAreaDTap = g_TCD.bAreaDTap * 0.001;	//[*0.1 %]
	g_fAreaPalm = g_TCD.bAreaPalm * 0.001;	//[*0.1 %]

	printf(">        TOUCH_FILTER_NUM : %d\r\n", g_TCD.bFilterNum);
	printf(">        TOUCH_INPUT_MODE : %d\r\n", g_TCD.bInputMode);
	printf(">              TOUCH_PWMS : %d %d %d %d\r\n",
		g_TCD.bPWMs[0], g_TCD.bPWMs[1], g_TCD.bPWMs[2], g_TCD.bPWMs[3]);
	printf(">          TOUCH_TIME_TAP : %d\r\n", g_TCD.bTimeTap);
	printf(">         TOUCH_TIME_LTAP : %d\r\n", g_TCD.bTimeLTap);
	printf(">          TOUCH_AREA_TAP : %d\r\n", g_TCD.bAreaTap);
	printf(">         TOUCH_AREA_DTAP : %d\r\n", g_TCD.bAreaDTap);
	printf(">         TOUCH_AREA_PALM : %d\r\n", g_TCD.bAreaPalm);
	printf(">        TOUCH_BEEP_ALERT : %d\r\n", g_TCD.bBeepAlert);
	printf(">        TOUCH_BEEP_CLICK : %d\r\n", g_TCD.bBeepClick);
	printf(">      TOUCH_TOUCH_NOSEND : %d\r\n", g_TCD.bTouchNoSend);

	printf(">      GESTURE_UDRAG(Hex) : %X %X\r\n",	g_GD.g[GE_DRAGUP].bFlag, g_GD.g[GE_DRAGUP].bKey);
	printf(">      GESTURE_RDRAG(Hex) : %X %X\r\n", g_GD.g[GE_DRAGRIGHT].bFlag, g_GD.g[GE_DRAGRIGHT].bKey);
	printf(">      GESTURE_DDRAG(Hex) : %X %X\r\n",	g_GD.g[GE_DRAGDOWN].bFlag, g_GD.g[GE_DRAGDOWN].bKey);
	printf(">      GESTURE_LDRAG(Hex) : %X %X\r\n",	g_GD.g[GE_DRAGLEFT].bFlag, g_GD.g[GE_DRAGLEFT].bKey);
	printf(">        GESTURE_TAP(Hex) : %X %X\r\n",	g_GD.g[GE_TAP].bFlag, g_GD.g[GE_TAP].bKey);
	printf(">       GESTURE_DTAP(Hex) : %X %X\r\n",	g_GD.g[GE_TAPDOUBLE].bFlag, g_GD.g[GE_TAPDOUBLE].bKey);
	printf(">       GESTURE_LTAP(Hex) : %X %X\r\n", g_GD.g[GE_TAPLONG].bFlag, g_GD.g[GE_TAPLONG].bKey);

	Usb_Init();
	USBD_Init(&g_UsbOtgDevice, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_HID_cb, &USR_cb);
	Pwm_Init(g_TCD.bPWMs);
	Touch_Init();
#elif	defined(BSP_DEVICE_CAMERA)
	if (DATA_EEPROM_START_VAL != uData)
	{
		printf(">		 APP_EEPROM_START : %04X != %04X\r\n", DATA_EEPROM_START_VAL, uData);
		printf("<<< EEPROM ALL DATA RESET >>>\r\n\r\n");

		g_CCD.nYCenter = DATA_YCENTER_DEF;
		g_CCD.wXStart = DATA_XSTART_DEF;
		g_CCD.wXEnd = DATA_XEND_DEF;
		g_CCD.bThreshold = DATA_THRESHOLD_DEF;
		g_CCD.bMinWidth = DATA_MINWIDTH_DEF;
		g_CCD.bAverageLight = DATA_AVERAGELIGHT_DEF;
		for (u8 i=0; i<DATA_COEFFS_NUM; i++) {
			g_CCD.fCoeffs[i] = 0;
		}

		EE_WriteVariable(g_VirtAddVarTab[CAMERA_YCENTER], g_CCD.nYCenter);
		EE_WriteVariable(g_VirtAddVarTab[CAMERA_XSTART], g_CCD.wXStart);
		EE_WriteVariable(g_VirtAddVarTab[CAMERA_XEND], g_CCD.wXEnd);
		EE_WriteVariable(g_VirtAddVarTab[CAMERA_THRESHOLD], g_CCD.bThreshold);
		EE_WriteVariable(g_VirtAddVarTab[CAMERA_MINWIDTH], g_CCD.bMinWidth);
		EE_WriteVariable(g_VirtAddVarTab[CAMERA_AVERAGELIGHT], g_CCD.bAverageLight);
		for (u8 i=0; i<DATA_COEFFS_NUM; i++) {
			float fValue = g_CCD.fCoeffs[i];
			u32 uValue = *(u32 *)&fValue;
			EE_WriteVariable(g_VirtAddVarTab[CAMERA_COEFFS_L0+(i<<1)], LOWORD(uValue));
			EE_WriteVariable(g_VirtAddVarTab[CAMERA_COEFFS_H0+(i<<1)], HIWORD(uValue));
		}

		uData = DATA_EEPROM_START_VAL;
		EE_WriteVariable(g_VirtAddVarTab[APP_EEPROM_START], uData);
	}
	else
	{
		EE_ReadVariable(g_VirtAddVarTab[CAMERA_YCENTER], &uData);
		{
			short yCenter = (short)uData;
			if (DATA_YCENTER_MIN > yCenter)
				g_CCD.nYCenter = DATA_YCENTER_MIN;
			else if (DATA_YCENTER_MAX < yCenter)
				g_CCD.nYCenter = DATA_YCENTER_MAX;
			else
				g_CCD.nYCenter = yCenter;
		}
		EE_ReadVariable(g_VirtAddVarTab[CAMERA_XSTART], &uData);
		g_CCD.wXStart = max(min(uData, DATA_XSTART_MAX), DATA_XSTART_MIN);
		EE_ReadVariable(g_VirtAddVarTab[CAMERA_XEND], &uData);
		g_CCD.wXEnd = max(min(uData, DATA_XEND_MAX), DATA_XEND_MIN);
		EE_ReadVariable(g_VirtAddVarTab[CAMERA_THRESHOLD], &uData);
		g_CCD.bThreshold = max(min(uData, DATA_THRESHOLD_MAX), DATA_THRESHOLD_MIN);
		EE_ReadVariable(g_VirtAddVarTab[CAMERA_MINWIDTH], &uData);
		g_CCD.bMinWidth = max(min(uData, DATA_MINWIDTH_MAX), DATA_MINWIDTH_MIN);
		EE_ReadVariable(g_VirtAddVarTab[CAMERA_AVERAGELIGHT], &uData);
		g_CCD.bAverageLight = max(min(uData, DATA_AVERAGELIGHT_MAX), DATA_AVERAGELIGHT_MIN);
		for (int i=0; i<DATA_COEFFS_NUM; i++) {
			u16 uL, uH;
			u32 uValue;
			EE_ReadVariable(g_VirtAddVarTab[CAMERA_COEFFS_L0+(i<<1)], &uL);
			EE_ReadVariable(g_VirtAddVarTab[CAMERA_COEFFS_H0+(i<<1)], &uH);
			uValue = MAKELONG(uL, uH);
			g_CCD.fCoeffs[i] = *(float *)&uValue;
		}
	}

	printf(">          CAMERA_YCENTER : %d\r\n", g_CCD.nYCenter);
	printf(">           CAMERA_XSTART : %d\r\n", g_CCD.wXStart);
	printf(">             CAMERA_XEND : %d\r\n", g_CCD.wXEnd);
	printf(">        CAMERA_THRESHOLD : %d\r\n", g_CCD.bThreshold);
	printf(">        CAMERA_MIN_WIDTH : %d\r\n", g_CCD.bMinWidth);
	printf(">    CAMERA_AVERAGE_LIGHT : %d\r\n", g_CCD.bAverageLight);
	printf(">           CAMERA_COEFFS : %f %f %f %f %f %f %f %f\r\n",
		g_CCD.fCoeffs[0], g_CCD.fCoeffs[1], g_CCD.fCoeffs[2], g_CCD.fCoeffs[3],
		g_CCD.fCoeffs[4], g_CCD.fCoeffs[5], g_CCD.fCoeffs[6], g_CCD.fCoeffs[7]);

	Cmos_Init();
#endif	//BSP_DEVICE_xxx

	g_u8CurState = STATE_INIT;
	while (1)
	{
		Uart_PktProc();
#if		defined(BSP_DEVICE_TOUCH)
		Touch_Proc();
		Usb_PktProc();
#elif	defined(BSP_DEVICE_CAMERA)
		Cmos_Proc();
#endif	//BSP_DEVICE_xxx
		procState(g_u8CurState);
		if (uDelay_ms <= g_vu32SysTickCount)
		{
			Led_Toggle(eLED_STATUS);
			uDelay_ms = g_vu32SysTickCount + 1000;
		}
	}
}

static void procState(u8 state)
{
	static u8 _oldState = STATE_UNKNOWN;

	if (_oldState != state)
	{
		switch (state)
		{
		case STATE_INIT:
			_CurStateProc = stateInit;
			break;
		case STATE_TOUCH:
			_CurStateProc = stateTouch;
			break;
		case STATE_SIDEVIEW:
			_CurStateProc = stateSideview;
			break;
		case STATE_DETECTION:
			_CurStateProc = stateDetection;
			break;
		case STATE_CALIBRATION:
			_CurStateProc = stateCalibration;
			break;

		default:
			printf("!!! stateChange(%d -> %d(Unknown))\r\n", _oldState, state);
			NVIC_SystemReset();
			return;
		}
		#if	DBG_MSG_APP
		printf("stateChange(%d -> %d)\r\n", _oldState, state);
		#endif	//DBG_MSG_APP
		_oldState = state;
#if		defined(BSP_DEVICE_TOUCH)
		g_u32BuzzerDelay = g_vu32SysTickCount + (10 * 10);	// *[10msec]
		Led_Set(eLED_BUZZER, 1);
		Touch_ChangeState(state);
#elif	defined(BSP_DEVICE_CAMERA)
		Cmos_ChangeState(state);
#endif	//BSP_DEVICE_CAMERA
	}

	_CurStateProc(state);
}

static void stateInit(u8 state)
{
	g_u8CurState = STATE_TOUCH;
#if		defined(BSP_DEVICE_TOUCH)
{
	u8 bReset = RESET_APP;
	for (u8 uart=eUART_MIN; uart<eUART_MAX; uart++)
		Uart_PktCmd(uart, CMD_RESET, (DEV_CAMERA1 + uart), 1, (u8 *)&bReset);
}
#elif	defined(BSP_DEVICE_CAMERA)
	Uart_PktEvt(eUART_TOUCH, EVT_CAMERA_INIT, g_u8MyAddr, sizeof(g_u8CurState), (u8 *)&g_u8CurState);
#endif
}
static void stateTouch(u8 state)
{
#if		defined(BSP_DEVICE_TOUCH)
#if	0
	if (g_u8TestCode) {
		INPUT_REPORT input = {0,};
		input.bReportId = REPORTID_KEYBOARD;

		static u8 _abSymbol[] = {
			// 0x54(/), 0x55(*), 0x56(-), 0x57(+), 0x2E(=), 0x2F([), 0x30(]), 0x31(\), 0x34('), 0x63(.)
			0x54, 0x55, 0x56, 0x57, 0x2E, 0x2F, 0x30, 0x31, 0x34, 0x63
		};
		static u8 _abEtc[] = {
			// 0x28(Enter), 0x29(Escape), 0x2A(Backspace), 0x2B(Tab), 0x2C(Spacebar), 0x49(Insert), 0x4A(Home),
			// 0x4B(PageUp), 0x4C(Delete), 0x4D(End), 0x4E(PageDown), 0x4F(Right), 0x50(Left), 0x51(Down), 0x52(Up)
			0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52
		};
		switch (g_u8TestCode&0x0F) {
		case 1:	// Function : F1(0x3A) ~ F12(0x45)
			for (int i=0; i<12; i++) {
				// pressed
				input.k.bButton = (g_u8TestCode&0xF0)>>4;	// [7(RGui) 6(RAlt) 5(RSft) 4(RCtl)] 3(LGui) 2(LAlt) 1(LSft) 0(LCtl)
				input.k.bKeys[0] = 0x3A + i;
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));

				printf("Function : %X %X\r\n", input.k.bButton, input.k.bKeys[0]);

				// released
				input.k.bButton = 0x00;
				input.k.bKeys[0] = 0x00;
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));
			}
			break;
		case 2:	// Number : 1(0x1E) ~ 0(0x27)
			for (int i=0; i<10; i++) {
				// pressed
				input.k.bButton = (g_u8TestCode&0xF0)>>4;	// [7(RGui) 6(RAlt) 5(RSft) 4(RCtl)] 3(LGui) 2(LAlt) 1(LSft) 0(LCtl)
				input.k.bKeys[0] = 0x1E + i;
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));

				printf("Number : %X %X\r\n", input.k.bButton, input.k.bKeys[0]);

				// released
				input.k.bButton = 0x00;
				input.k.bKeys[0] = 0x00;
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));
			}
			break;
		case 3:	// Alphabet : A(0x04) ~ Z(0x1D)
			for (int i=0; i<26; i++) {
				// pressed
				input.k.bButton = (g_u8TestCode&0xF0)>>4;	// [7(RGui) 6(RAlt) 5(RSft) 4(RCtl)] 3(LGui) 2(LAlt) 1(LSft) 0(LCtl)
				input.k.bKeys[0] = 0x04 + i;
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));

				printf("Alphabet : %X %X\r\n", input.k.bButton, input.k.bKeys[0]);

				// released
				input.k.bButton = 0x00;
				input.k.bKeys[0] = 0x00;
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));
			}
			break;
		case 4:	// Symbol
			for (int i=0; i<_countof(_abSymbol); i++) {
				// pressed
				input.k.bButton = (g_u8TestCode&0xF0)>>4;	// [7(RGui) 6(RAlt) 5(RSft) 4(RCtl)] 3(LGui) 2(LAlt) 1(LSft) 0(LCtl)
				input.k.bKeys[0] = _abSymbol[i];
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));

				printf("Symbol : %X %X\r\n", input.k.bButton, input.k.bKeys[0]);

				// released
				input.k.bButton = 0x00;
				input.k.bKeys[0] = 0x00;
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));
			}
			break;
		case 5:	// Etc
			for (int i=0; i<_countof(_abEtc); i++) {
				// pressed
				input.k.bButton = (g_u8TestCode&0xF0)>>4;	// [7(RGui) 6(RAlt) 5(RSft) 4(RCtl)] 3(LGui) 2(LAlt) 1(LSft) 0(LCtl)
				input.k.bKeys[0] = _abEtc[i];
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));

				printf("Etc : %X %X\r\n", input.k.bButton, input.k.bKeys[0]);

				// released
				input.k.bButton = 0x00;
				input.k.bKeys[0] = 0x00;
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));
			}
			break;
		case 6:	// Flag
			{
				// pressed
				input.k.bButton = (g_u8TestCode&0xF0)>>4;	// [7(RGui) 6(RAlt) 5(RSft) 4(RCtl)] 3(LGui) 2(LAlt) 1(LSft) 0(LCtl)
				input.k.bKeys[0] = 0x00;
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));

				printf("Flag : %X %X\r\n", input.k.bButton, input.k.bKeys[0]);

				// released
				input.k.bButton = 0x00;
				input.k.bKeys[0] = 0x00;
				SendReport_Input(&g_UsbOtgDevice, (u8 *)&input, sizeof(input));
			}
			break;
		}

		g_u8TestCode = 0;
	}
#endif
#endif
}
static void stateSideview(u8 state)
{
}
static void stateDetection(u8 state)
{
}
static void stateCalibration(u8 state)
{
}

